perm filename FASFRK.JP[LIB,LSP] blob sn#864797 filedate 1977-07-20 generic text, type C, neo UTF8
COMMENT ⊗   VALID 00004 PAGES
C REC  PAGE   DESCRIPTION
C00001 00001
C00002 00002			SAIL MACLISP Interjob Communication Facility
C00008 00003	Short description of available forking functions
C00010 00004	An example of how to setup two forks
C00013 ENDMK
C⊗;
		SAIL MACLISP Interjob Communication Facility
		--------------------------------------------

By: JP (Jorge Phillips) @ SAIL

A preliminary  version of  a MACLISP  interjob communication  facility  is
available to  all  lusers subscribing  to  the (help)  autoload  facility.
These functions permit arbitrary  creation, deletion, synchronization  and
intercommunication of MACLISP  processes (SAIL  jobs). For the  sake of  a
better name, and  to confuse everybody  we will refer  to MACLISP jobs  as
forks (although there  is no  hierarchical structure between  jobs as  the
name would imply).

Forks are uniquely identified by  job number (assigned by SAIL-10)  during
their existence. To a MACLISP job a fork is identified by its fork handle,
which is nothing but its FIXNUMified  job number. There are functions  for
creating parent and child  MACLISP processes, and  to suspend them.  There
are also functions for  sending sxprs between  forks and for  busy-waiting
and/or blocking  for  messages  either  from  particular  forks  or  of  a
particular value.

The process of creating and using forks is as follows:
	- forks that will be called below the monitor top-level must execute
	  the subr sfork in order to suspend themselves in a nice way
	  These forks are ssaved as dump files to be called by their
	  parent fork.
	- A suspended fork ssaved on DSK: is reactivated by the CFORK subr.
	  This subr must be applied by the parent fork (the creator), and
	  starts the child fork exactly after the SFORK that suspended it.
	- CFORK and SFORK return the fork handles for the created child fork
	  and for the parent fork respectively. They also set the global
	  vars UPFORK# (in the child) and LOWFRK# (in the parent).
	- A child fork (i.e. a non-top level fork) kills itself and dissapears
	  by applying (quit)
	- So does the top-level MACLISP job.

NOTICE: If a fork hits  a LISP error condition,  it will NOT kill  itself.
You will  have to  kill it  manually,  or advise  somehow the  LISP  error
handler to execute  a (quit)  previously having  sent some  kind of  death
message to  its parent  (unless  the parent  fork  doesnt care,  which  is
unlikely). Better even, you  might have the fork  send back to its  parent
some message and let the parent decide what action to take. You may attach
to a  fork to  regain control  of the  tty, and  take whatever  action  is
appropriate in the break.

Intercommunication
------------------

MACLISP interjob mesages are of  the format (fork-handle . message)  where
message is an sxpr (atoms allowed). A typical message might be:
	(27 . hi)
which means that it was  originated from fork 27,  and the message is  the
atom hi.  Messages can  be of up to  5120 chars including parens,  blanks,
escape chars etc.  This  allows to send  messages of at  most 10 pages  of
tightly packed parens, which should be sufficient for most applications.
If you need messages of a larger size, you'd better write them in a file,
and send messages with the file name. You will clearly have to synchronize
the file reading and writing.

NOTE: Losing MACLISP screws up transmission of |..| atoms. They will arrive
w/o the |..|. Thus, |a b foo| will be received as a b foo. BEWARE!!
Short description of available forking functions
------------------------------------------------

	cfork[(filnam ext p pn)]   SUBR
		Starts up a  suspended fork. Sets  global lowfrk# to  fork
		handle. Returns this as value in  case you want to use  it
		for something else

	sfork[]	SUBR
		Suspends fork and returns when CFORKed, the parent's handle.
		It also sets global UPFORK# to the handle.
	
	msg[frk# sxpr] SUBR
		Sends s-expression  sxpr to  fork frk#.  It returns  T  if
		succesful, NIL if the fork is busy reading a msg, or NOJOB  if
		the fork is non-existent. If  NIL is returned the  message
		must be resent.

	gmsg[] SUBR
		Blocks calling process, waiting for message from  anybody.
		Returns message as dotted pair (frk# . sxpr). No software
		interrupts (such as ↑G) are acknowledged in this state.

	waitmsg[msg frk#] SUBR
		Busy waits for a  message EQ to msg  from fork FRK#.  NILs
		act as wildcards. A frk# of NIL accepts a message from ANY
		fork.   A   msg   NIL   accepts   any   message.   Clearly
		waitmsg[nil;nil] is equivalent to gmsg[]

	mail?[] SUBR
		T if msg waiting, NIL otherwise.
An example of how to setup two forks
------------------------------------

;;; Upper fork initialization functions. To get a SUSPENDed version do
;;; (start-forking) at top-level Lisp.

;;; This would be a file to EREAD into a clean LISP to create a parent fork.
;;; In this case, the parent fork calls the lower fork to reverse an sxpr
;;; if the sxpr is a list or listify it if it is an atom. If it gets something
;;; else, the lower fork will bomb (no type checking is done).

(defun fork-read nil
	(terpri)(princ '|-->|)(read))

(defun fork-print nil
	(princ '|from frk: |)(princ (cdr (gmsg)) ))

(defun fork-fork nil
      (do ((x (fork-read) (fork-read)))
	  ((eq x 'end) (prog2 (print ':kill) (quit))) 
	  (msg lowfrk# x)
	  (fork-print) ))

(defun start-forking nil
	(suspend)
        (cfork (prog2 (princ '|Lower fork name? |)(read))) 
        (fork-fork) )

⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗
;;;  down fork initialization fns. To get a SUSPENDed version do (start-forking)
;;;  at top-level Lisp. Fork dissapears magically previously having sent the message
;;;  (DIE! DIE!) to its parent

;;;  And you would EREAD this into another LISP to get the suspended version of
;;;  the child fork.

(defun fork-fork nil
      (do ((x (cdr (gmsg)) (cdr (gmsg)) ))
	  ((eq x 'STOP)(msg upfork# '(die! die!))(quit))
	  (msg upfork# (cond ((atom x)(list x))
			     (t (reverse x))))))
(defun start-forking nil
(prog2 (sfork)(fork-fork)))